package com.beta.auth.exception;


import com.beta.auth.common.ResultVo;
import com.beta.user.auth.center.api.response.CommonResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;


@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 缺失请求参数，比如使用了@NotNull注解
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ResultVo<Object> bindExceptionHandler(MissingServletRequestParameterException exception) {
        log.error(exception.getMessage(), exception);
        return ResultVo.failure(CommonResultEnum.MISSING_REQUEST_PARAMETER.getState(), exception.getMessage());
    }


    /**
     * 参数校验失败，该异常来自于表单验证框架 Hibernate validation，当字段验证未通过时会抛出此异常
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResultVo<Object> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException exception) {
        log.error(exception.getMessage(), exception);
        return ResultVo.failure(CommonResultEnum.PARAMETER_VERIFICATION_ABNORMAL.getState(), exception.getBindingResult().getFieldError().getDefaultMessage());
    }


    /**
     * 参数类型不匹配，比如说后端需要Integer类型，但是前端传过来是String类型的
     */
    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    public ResultVo<Object> methodArgumentTypeMismatchExceptionHandler(MethodArgumentTypeMismatchException exception) {
        log.error(exception.getMessage(), exception);
        return ResultVo.failure(CommonResultEnum.PARAMETER_TYPE_DOES_NOT_MATCH.getState(), exception.getMessage());
    }


    /**
     * 请求方式异常
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public ResultVo<Object> httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException exception) {
        log.error(exception.getMessage(), exception);
        return ResultVo.failure(CommonResultEnum.REQUEST_METHOD_IS_ABNORMAL.getState(), "不支持" + exception.getMethod() + "请求");
    }


    /**
     * 解析参数失败，比如说后端需要时间格式是yyyy-MM-dd HH:mm:ss，前端穿的是yyyy-MM-dd HH:mm:sss
     */
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    public ResultVo<Object> httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException exception) {
        log.error(exception.getMessage(), exception);
        return ResultVo.failure(CommonResultEnum.FAILED_TO_PARSE_PARAMETERS.getState(), exception.getMessage());
    }


    /**
     * 业务异常处理，手动抛出的BusinessException异常
     */
    @ExceptionHandler(value = BusinessException.class)
    private ResultVo<Object> businessExceptionHandler(BusinessException exception) {
        log.error(exception.getMessage(), exception);
        return ResultVo.failure(exception.getCode(), exception.getMsg());
    }


    /**
     * 程序运行过程中出现的未知异常, 例如：ArrayIndexOutOfBoundsException, NullPointerException
     * 这种错误应该在测试阶段就避免, 按理说是不应该在生产环境产生的，但是防止万一所以这里就统一对外友好提示
     */
    @ExceptionHandler(value = Exception.class)
    public ResultVo<Object> exceptionHandler(Exception exception) {
        log.error(exception.getMessage(), exception);
        return ResultVo.failure(CommonResultEnum.SYSTEM_HAS_MALFUNCTIONED);
    }
}
